package cn.ante.ymcc.service.impl;

import cn.ante.ymcc.doc.CourseDoc;
import cn.ante.ymcc.dto.Aggs;
import cn.ante.ymcc.dto.CourseEsSearchDto;
import cn.ante.ymcc.esmapper.HighlightResultMapper;
import cn.ante.ymcc.repository.CourseElasticsearchRepository;
import cn.ante.ymcc.result.PageList;
import cn.ante.ymcc.service.ICourseESService;
import cn.ante.ymcc.utils.AggPageList;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class CourseESServiceImpl implements ICourseESService {
    @Autowired
    private CourseElasticsearchRepository courseElasticsearchRepository;

    @Autowired
    private ElasticsearchRestTemplate elasticsearchRestTemplate;

    @Autowired
    private HighlightResultMapper highlightResultMapper;

    @Override
    public void saveElasticSearch(CourseDoc courseDoc) {
        courseElasticsearchRepository.save(courseDoc);
    }

    @Override
    public void removeElasticSearch(Long id) {
        courseElasticsearchRepository.deleteById(id);
    }

    /**
    * @Description: es分页查询
    * @Author: Nai
    * @Version: 1.0
    * @Date:  2022/8/15 15:10
     *   private Long courseTypeId;
     *     private String gradeName;
     *     private BigDecimal priceMin;
     *     private BigDecimal priceMax;
     *     private String sortField;
     *     private String sortType;
    */
    @Override
    public PageList<CourseDoc> search(CourseEsSearchDto dto) {
        // 找到分页方法,使用es方法查询
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        // 设置查询结果展示
        queryBuilder.withPageable(PageRequest.of(dto.getPage() - 1, dto.getRows()));

        // 排序条件--------当传入字段不为空的时候，就匹配相应的需要排序的字段
        if (StringUtils.hasLength(dto.getSortField())){
            String sortName = "";
            switch (dto.getSortField().toLowerCase()){
                case "xl": sortName = "saleCount";break;
                case "pl": sortName = "commentCount";break;
                case "jg": sortName = "price";break;
                case "rq": sortName = "viewCount";break;
                case "xp": sortName = "onlineTime";break;
            }
            // 当排序的字段不为空时就排序
            if (sortName != null){
                SortOrder order = SortOrder.DESC;
                if (dto.getSortType() != null){
                    order = dto.getSortType().equalsIgnoreCase("DESC")? SortOrder.DESC :SortOrder.ASC;
                }
                queryBuilder.withSort(SortBuilders.fieldSort(sortName).order(order));
            }
        }
        // 搜索条件-------但关键词不为空时，分词查找
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        if (StringUtils.hasLength(dto.getKeyword())){
            // 设置课程名字查找
            boolQuery.must(QueryBuilders.matchQuery("name",dto.getKeyword()));
        }
        // 课程类型查找
        if (dto.getCourseTypeId() != null) {
            boolQuery.filter(QueryBuilders.termQuery("courseTypeId", dto.getCourseTypeId()));
        }
        // 课程等级查找
        if (dto.getGradeName() != null){
            boolQuery.filter(QueryBuilders.termQuery("gradeName",dto.getGradeName()));
        }
        // 课程最小价格查找
        if (dto.getPriceMin() != null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").gte(dto.getPriceMin()));
        }
        // 课程最大价格查找
        if (dto.getPriceMax() != null){
            boolQuery.filter(QueryBuilders.rangeQuery("price").lte(dto.getPriceMax()));
        }
        // 放入查询条件
        queryBuilder.withQuery(boolQuery);

        // 高亮-----设置高亮条件
        queryBuilder.withHighlightFields(new HighlightBuilder
                .Field("name").preTags("<font style = 'color:purple'>").postTags("</font>"));
        //-----------聚合：设置聚合条件
        queryBuilder.addAggregation(AggregationBuilders.terms("gradeAggNames").field("gradeName"));
        queryBuilder.addAggregation(AggregationBuilders.terms("chargeAggNames").field("chargeName"));

        NativeSearchQuery build = queryBuilder.build();
        // 处理高亮结果-----------
        AggregatedPage<CourseDoc> page = elasticsearchRestTemplate.queryForPage(build, CourseDoc.class, highlightResultMapper);
        //-------处理聚合结果
        Aggregations aggregations = page.getAggregations();
        Map<String, Aggregation> aggregationMap = aggregations.asMap();
        ParsedStringTerms gradeAggNames = (ParsedStringTerms)aggregationMap.get("gradeAggNames");
        ParsedStringTerms chargeAggNames = (ParsedStringTerms)aggregationMap.get("chargeAggNames");
        List<Aggs> gradeAggNameList = gradeAggNames.getBuckets().stream().map(bucket -> new Aggs(bucket.getKeyAsString(), bucket.getDocCount()))
                .collect(Collectors.toList());
        List<Aggs> chargeAggNameList = chargeAggNames.getBuckets().stream().map(bucket -> new Aggs(bucket.getKeyAsString(), bucket.getDocCount()))
                .collect(Collectors.toList());
        HashMap<String, List<Aggs>> map = new HashMap<>();
        map.put("gradeAggNames",gradeAggNameList);
        map.put("chargeAggNames",chargeAggNameList);
        //        Page<CourseDoc> search = courseElasticsearchRepository.search(build);
        return new AggPageList(page.getTotalElements(),page.getContent(),map);
    }
}
